package com.culture.config.util;

import java.io.BufferedWriter;
import java.io.StringWriter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.LinkedList;

import com.culture.config.common.model.BusinessException;
import com.culture.config.dao.entity.Property;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.dataformat.javaprop.JavaPropsFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;

import org.apache.commons.collections4.CollectionUtils;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@UtilityClass
public class PropertiesUtil { 
    final String DOT = ".";

    public List<Property> ymlToProperties(String content) {   
        List<Property> properties = new LinkedList<>();       
        try {
            YAMLFactory yamlFactory = new YAMLFactory();            
            YAMLParser parser = yamlFactory.createParser(content);           
            StringBuilder key = new StringBuilder();           
            JsonToken token = parser.nextToken();
            while (token != null) {
                if (JsonToken.FIELD_NAME.equals(token)) {
                    if (key.length() > 0) {
                        key.append(DOT);                        
                    }                   
                    key.append(parser.getCurrentName());
                    token = parser.nextToken();
                    if (JsonToken.START_OBJECT.equals(token)) {
                        continue;
                    }                
                    properties.add(new Property(key.toString(),parser.getText()));
                    int dotOffset = key.lastIndexOf(DOT);
                    if (dotOffset > 0) {  
                        key.delete(dotOffset,key.length());
                    }                    
                } 
                if (JsonToken.END_OBJECT.equals(token)) {
                    handeEnd(key);
                }
                token = parser.nextToken();
            }
            parser.close();
            log.info("ymlToProperties:{}",properties);
        } catch (Exception e) {
            throw new BusinessException(e);
        }
        return properties;
    }    

    private void handeEnd(StringBuilder key){
        int dotOffset = key.lastIndexOf(DOT);
        if (dotOffset > 0) {
            key.delete(dotOffset,key.length());                       
        } else {
            key.delete(0,key.length());          
        }
    }

    public String propertiesToYaml(List<Property> properties){
        String yamlStr = null; 
        StringWriter sw = new StringWriter(2048);
        JavaPropsFactory factory = new JavaPropsFactory();
        YAMLFactory yamlFactory = new YAMLFactory();
        try(JsonParser parser = factory.createParser(toMap(properties));
            BufferedWriter bufferedWriter = new BufferedWriter(sw);  
            YAMLGenerator generator = yamlFactory.createGenerator(bufferedWriter);
        ) {
            JsonToken token = parser.nextToken();
            while (token != null) {
                if (JsonToken.START_OBJECT.equals(token)) {
                    generator.writeStartObject();
                } else if (JsonToken.FIELD_NAME.equals(token)) {
                    generator.writeFieldName(parser.getCurrentName());
                } else if (JsonToken.VALUE_STRING.equals(token)) {
                    generator.writeString(parser.getText());
                } else if (JsonToken.END_OBJECT.equals(token)) {
                    generator.writeEndObject();
                }
                token = parser.nextToken();
            }            
            generator.flush();           
            bufferedWriter.flush();           
            yamlStr = sw.toString();           
        } catch (Exception e) {
            log.error("propertiesToYaml exception:{}",e);
        }
        return yamlStr;
    }

    public Map<String, Object> toMap(List<Property> properties){
        if(CollectionUtils.isEmpty(properties)){
			return Collections.emptyMap();
		}	
        Map<String, Object> propertiesMap = new LinkedHashMap<>();
        properties.forEach(e->propertiesMap.put(e.getPropertyKey(), e.getPropertyValue()));
        return propertiesMap;
    }   
}
